const router = require('koa-router')()
const Redis = require('koa-redis') 

const nodeMailer = require('nodemailer')
const User = require('../dbs/models/users')
const Passport = require('./utils/passport')
const Email = require('../dbs/config')
const axios = require('./utils/axios')

router.prefix('/users')
// let router = new Router({
//   prefix: "/users"
// })

// 获取Redis客户端
let Store = new Redis().client

/**
  * @api {post} /users/signup 注册接口
  * @apiDescription 注册接口
  * @apiName signup
  * @apiGroup users
  * @apiParam {string} username 用户名
  * @apiParam {string} password 密码
  * @apiParam {string} email 邮箱
  * @apiParam {string} code 验证码
  * @apiSuccess {json} result
  * @apiSuccessExample {json} Success-Response:
  * {
      code: 0,
      msg: "注册成功",
      user: res.data.user
    }
  * @apiSampleRequest http://localhost:3000/api/users/signup
  */
router.post("/signup", async (ctx)=>{
  const {
    username,
    password,
    email,
    code
  } = ctx.request.body; //post方式

  if(code) {
    // 从Redis里获取存储的验证码  在发送验证码是存储了这个验证码
    // 存的格式已键值对的方式存储 `nodemail:${username}` 
    // `nodemail:${username}` nodemail自定义的 username用户名用于 在发送验证码是跟用户名绑定的
    // 取的键值是code
    const saveCode = await Store.hget(`nodemail:${username}`, "code");
    // 获取过期时间
    // 取的键值是expire
    const saveExpire = await Store.hget(`nodemail:${username}`, "expire");
    // 判断用户输入的验证码是否和存储的验证码相同
    if(code === saveCode) {
      if(new Date().getTime() - saveExpire > 0) {
        ctx.body = {
          code: -1,
          msg: "验证吗已过期，请重新尝试"
        }
        return false;
      }
    } else {
      ctx.body = {
        code: -1,
        msg: "请填写正确的验证码"
      }
    }
  } else {
    ctx.body = {
      code: -1,
      msg: "请填写验证码"
    }
  }

  // 查询用户信息  
   let user = null
  try {
    user = await User.find({
      username
    })
    console.log('user',user)
  } catch(err) {
    console.log("err", err)
    user = []

  }  
 // 用户已存在   
  if(user.length) {
    ctx.body = {
      code: -1,
      msg: "用户名已被注册"
    }
    return
  }
  // 将该用户存储到数据库中  
  let nuser = await User.create({
    username,
    password,
    email
  })
  
  // 成功后   
  if(nuser) {
    // 暂时不需要登录
    ctx.body = {
      code: 0,
      msg: "注册成功",
      user: {
        username,
        password
      }
    }

    //   进行登录
    /*
      let res = await axios.post('/users/signin', {
        username,
        password
      })
      
      if(res.data && res.data.code === 0) {
        ctx.body = {
          code: 0,
          msg: "注册成功",
          user: res.data.user
        }
      } else {
        ctx.body = {
          code: -1,
          msg: "error"
        }
      } 
    */
  } else {
    ctx.body = {
      code: -1,
      msg: "注册失败"
    }
  } 
})

/**
  * @api {post} /users/signin 登录接口
  * @apiDescription 登录接口
  * @apiName signin
  * @apiGroup users
  * @apiParam {string} username 用户名
  * @apiParam {string} password 密码
  * @apiSuccess {json} result
  * @apiSuccessExample {json} Success-Response:
  * {
  *   code: 0,
  *   msg: "登录成功",
  *   user
  * }
  * @apiSampleRequest http://localhost:3000/api/users/signin
  */
router.post('/signin', async (ctx, next)=>{
  return Passport.authenticate("local", function(err, user, info, status){
    /*这是回调函数，这里的四个参数就是策略中的done返回的四个参数，当然这都是由自己决定的，可以选择返回更多或更少的参数*/
    if(err) {
      ctx.body = {
        code: -1,
        msg: err
      }
    } else {
      if(user) {
        ctx.body = {
          code: 0,
          msg: "登录成功",
          user
        }
        //这里调用ctx.login()函数传入的参数要和上文中的序列化函数passport.serializeUser对应
        return ctx.login(user)
      } else {
        ctx.body = {
          code: 1,
          msg: info
        }
      }
    }
  })(ctx, next) //此处将ctx传入本地验证策略函数
})
router.get("/fix", async (ctx)=>{
  //Store.hset(`test`, "name", "111");
  ctx.session.name = "nidie";
  ctx.body = {
    code:0
  }
})

/**
  * @api {post} /users/verify 验证码接口
  * @apiDescription 验证码接口
  * @apiName verify
  * @apiGroup users
  * @apiParam {string} username 用户名
  * @apiParam {string} email 邮箱
  * @apiSuccess {json} result
  * @apiSuccessExample {json} Success-Response:
  * {
  *  code: 0,
  *  msg: "验证码已经发送，可能会有延时，有效期1分钟",
  *  data: mailOptions
  * }
  * @apiSampleRequest http://localhost:3000/api/users/verify
  */
router.post("/verify", async(ctx, next)=>{
  let username = ctx.request.body.username;
  // 获取验证码过期时间   
  const saveExpire = await Store.hget(`nodemail:${username}`, "expire")
  if(saveExpire && new Date().getTime() - saveExpire < 0) {
    ctx.body = {
      code: -1,
      msg: "验证请求过于频繁，1分钟内1次"
    }
    return false
  }
  // 创建发邮件的实例   
  let transporter = nodeMailer.createTransport({
    host: Email.smtp.host,
    port: Email.smtp.port,
    secure: false, // true是监听405端口 false是监听其它端口
    auth: {
      user: Email.smtp.user,
      pass: Email.smtp.pass
    }
  })
   // 对外发送哪些信息和发给谁的参数配置   
  let ko = {
    code: Email.smtp.code(),
    expire: Email.smtp.expire(),
    email: ctx.request.body.email,
    user: ctx.request.body.username
  }
  // 邮件显示的内容   
  let mailOptions = {
    from: `认证邮件<${Email.smtp.user}>`, // 发件方
    to: ko.email, // 接收方
    subject: "《慕课网高仿美团网全栈实战》注册码", // 邮件主题
    html: `您在《慕课网高仿美团网全栈实战》课程中注册，您的邀请码是${ko.code}` // 邮件内容
  }
  // 将邮件发送到相对应的邮箱
  // 进行邮件发送   
  /* await transporter.sendMail(mailOptions, (err, info)=>{
    if(err) {
      return console.log(err);
    } else {
      // 存储hmset 存储的内容是user、code、expire、expire、email
      Store.hmset(`nodemail:${ko.user}`, 'code', ko.code, 'expire', ko.expire, 'email', ko.email)
    }
  }) */

  // 存储hmset 存储的内容是user、code、expire、expire、email
  Store.hmset(`nodemail:${ko.user}`, 'code', ko.code, 'expire', ko.expire, 'email', ko.email)
  ctx.body = {
    code: 0,
    msg: "验证码已经发送，可能会有延时，有效期1分钟",
    data: mailOptions
  }
}) 

/**
  * @api {post} /users/exit 退出登录
  * @apiDescription 退出登录
  * @apiName exit
  * @apiGroup users
  * @apiSuccess {json} result
  * @apiSuccessExample {json} Success-Response:
  * {
  *   code: 0
  * }
  * @apiSampleRequest http://localhost:3000/api/users/exit
  */
router.get('/exit', async (ctx, next)=>{
  await ctx.logout()
  // 当你在其他路由中需要验证用户是否登录的时候就可以通过ctx.isAuthenticated()函数，这样：
  //  isAuthenticated用于检测是否登录状态
  if(!ctx.isAuthenticated()) {
    ctx.body = {
      code: 0
    }
  } else {
    ctx.body = {
      code: -1
    }
  }
})
/**
 * 
 */
/**
  * @api {post} /users/getUser 获取用户信息
  * @apiDescription 获取用户信息
  * @apiName getUser
  * @apiGroup users
  * @apiParam {string} username 用户名
  * @apiParam {string} email 邮箱
  * @apiSuccess {json} result
  * @apiSuccessExample {json} Success-Response:
  * {
  *   code: 0
  * }
  * @apiSampleRequest http://localhost:3000/api/users/getUser
  */
router.get('/getUser', async (ctx)=>{
  // 检测是否登录状态 
  if(ctx.isAuthenticated()) {
    // 在session中获取存储的用户信息
    // passport是存储在session中的所有可以在session中获取到用户信息
    const {username, email} = ctx.session.passport.user
    ctx.body = {
      user: username,
      email
    }
  } else {
    ctx.body = {
      user: "",
      email: ""
    }
  }
})

// 以上有三个方法login，logout，isAuthenticated，是passport模块加进来的方法，出了这三个还有一个isUnauthenticated，其作用和isAuthenticated相反，除了login方法外，其他三个都不带参数
// export default router;
module.exports = router
